<template>
  <!-- 把选择的颜色同步到左侧侧边栏Sidebar和顶部导航栏Navbar中
ElementUi组件库不需要我们更换ThemePicker组件做了 -->
  <!-- 思路:把选择的颜色分别给 Sidebar和Navbar的背景赋值
ThemePicker, Sidebar, Navk+这3个组件需要共享数据
并且还得是响应式，所用用 vuex 管理颜色值 -->
  <el-color-picker
    v-model="theme"
    :predefine="[
      '#409EFF',
      '#1890ff',
      '#304156',
      '#212121',
      '#11a983',
      '#13c2c2',
      '#6959CD',
      '#f5222d',
      '#E6C3C3',
    ]"
    class="theme-picker"
    popper-class="theme-picker-dropdown"
  />
</template>

<script>
const version = require("element-ui/package.json").version; // element-ui version from node_modules
const ORIGINAL_THEME = "#409EFF"; // default color
export default {
  name: "ThemePicker",
  data() {
    return {
      chalk: "", // content of theme-chalk css
      theme: "",
    };
  },
  computed: {
    defaultTheme() {
      return this.$store.state.settings.theme;
    },
  },
  watch: {
    defaultTheme: {
      handler: function (val, oldVal) {
        this.theme = val;
      },
      immediate: true, //让handler函数在初始化的时候立即执行一次
    },
    //侦听theme这个数据
    //变了之后，去请求新的网络样式资源文件，覆盖默认样式了
    theme: {
      async handler(val) {
        // 触发settings/changeSetting函数，把选择的颜色同步到vuex中
        this.$store.dispatch("settings/changeSetting", {
          key: "theme",
          value: val,
        });
        const oldVal = this.chalk ? this.theme : ORIGINAL_THEME;
        if (typeof val !== "string") return;
        const themeCluster = this.getThemeCluster(val.replace("#", ""));
        const originalCluster = this.getThemeCluster(oldVal.replace("#", ""));
        console.log(themeCluster, originalCluster);
        const $message = this.$message({
          message: "  Compiling the theme",
          customClass: "theme-message",
          type: "success",
          duration: 0,
          iconClass: "el-icon-loading",
        });
        const getHandler = (variable, id) => {
          return () => {
            const originalCluster = this.getThemeCluster(
              ORIGINAL_THEME.replace("#", "")
            );
            const newStyle = this.updateStyle(
              this[variable],
              originalCluster,
              themeCluster
            );
            let styleTag = document.getElementById(id);
            if (!styleTag) {
              styleTag = document.createElement("style");
              styleTag.setAttribute("id", id);
              document.head.appendChild(styleTag);
            }
            styleTag.innerText = newStyle;
          };
        };
        if (!this.chalk) {
          const url = `https://unpkg.com/element-ui@${version}/lib/theme-chalk/index.css`;
          await this.getCSSString(url, "chalk");
        }
        const chalkHandler = getHandler("chalk", "chalk-style");
        chalkHandler();
        const styles = [].slice
          .call(document.querySelectorAll("style"))
          .filter((style) => {
            const text = style.innerText;
            return (
              new RegExp(oldVal, "i").test(text) &&
              !/Chalk Variables/.test(text)
            );
          });
        styles.forEach((style) => {
          const { innerText } = style;
          if (typeof innerText !== "string") return;
          style.innerText = this.updateStyle(
            innerText,
            originalCluster,
            themeCluster
          );
        });
        this.$emit("change", val);
        $message.close();
      },
      immediate: true,
    },
  },
  methods: {
    updateStyle(style, oldCluster, newCluster) {
      let newStyle = style;
      oldCluster.forEach((color, index) => {
        newStyle = newStyle.replace(new RegExp(color, "ig"), newCluster[index]);
      });
      return newStyle;
    },
    getCSSString(url, variable) {
      return new Promise((resolve) => {
        const xhr = new XMLHttpRequest();
        xhr.onreadystatechange = () => {
          if (xhr.readyState === 4 && xhr.status === 200) {
            this[variable] = xhr.responseText.replace(/@font-face{[^}]+}/, "");
            resolve();
          }
        };
        xhr.open("GET", url);
        xhr.send();
      });
    },
    getThemeCluster(theme) {
      const tintColor = (color, tint) => {
        let red = parseInt(color.slice(0, 2), 16);
        let green = parseInt(color.slice(2, 4), 16);
        let blue = parseInt(color.slice(4, 6), 16);
        if (tint === 0) {
          // when primary color is in its rgb space
          return [red, green, blue].join(",");
        } else {
          red += Math.round(tint * (255 - red));
          green += Math.round(tint * (255 - green));
          blue += Math.round(tint * (255 - blue));
          red = red.toString(16);
          green = green.toString(16);
          blue = blue.toString(16);
          return `#${red}${green}${blue}`;
        }
      };
      const shadeColor = (color, shade) => {
        let red = parseInt(color.slice(0, 2), 16);
        let green = parseInt(color.slice(2, 4), 16);
        let blue = parseInt(color.slice(4, 6), 16);
        red = Math.round((1 - shade) * red);
        green = Math.round((1 - shade) * green);
        blue = Math.round((1 - shade) * blue);
        red = red.toString(16);
        green = green.toString(16);
        blue = blue.toString(16);
        return `#${red}${green}${blue}`;
      };
      const clusters = [theme];
      for (let i = 0; i <= 9; i++) {
        clusters.push(tintColor(theme, Number((i / 10).toFixed(2))));
      }
      clusters.push(shadeColor(theme, 0.1));
      return clusters;
    },
  },
};
</script>

<style>
.theme-message,
.theme-picker-dropdown {
  z-index: 99999 !important;
}
.theme-picker .el-color-picker__trigger {
  height: 26px !important;
  width: 26px !important;
  padding: 2px;
}
.theme-picker-dropdown .el-color-dropdown__link-btn {
  display: none;
}
.el-color-picker {
  height: auto !important;
}
</style>
